/**
 * Copyright 2012 Roger Cockshutt
 * krakenbrau@gmail.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.googlecode.parallelrl.util;

/**
 * @author Roger Cockshutt
 *
 */
public final class MersenneTwister {
	
	private static long[] twister = new long[624];
	private static int index = 0;
	
	
	
	public static void initialize(long seed) {
		twister[0] = seed;
		for (int i = 1; i < 624; i++) {
			twister[i] = (0x6c078965 * (twister[i - 1] ^ (twister[i - 1] >>> 30)) + i) & 0xFFFF;
		}
	}
	
	public static long extractNumber() {
		if (index == 0) {
			generateNumbers();
		}
		
		long y = twister[index];
		y ^= (y >>> 11);
		y ^= ((y << 7) & 0x9d2c5680);
		y ^= ((y << 15) & 0xefc60000);
		y ^= (y >>> 18);
		
		index = (index + 1) % 624;
		return y;
	}
	
	private static void generateNumbers() {
		for (int i = 0; i < 624; i++) {
			long y = (twister[i] & 0x80000000) + (twister[(i + 1) % 624] & 0x7FFFFFFF);
			twister[i] = twister[(i + 397) % 624] ^ (y >>> 1);
			if (y % 2 != 0) {
				twister[i] ^= 0x9908b0df;
			}
		}
	}
	
	public static int getNext(int mod) {
		return (int) Math.abs((extractNumber() % mod));		// For some reason, MT occasionally returns negative values.
	}
	
	public static int rollDice(int numDice, int numSides) {
		int total = 0;
		for (int i = 0; i < numDice; i++) {
			total += getNext(numSides) + 1;
		}
		return total;
	}
	
	
	private MersenneTwister(){}

}
